package com.qf.user.manager.filter;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.qf.common.model.QfUser;
import com.qf.common.utils.JsonUtil;
import com.qf.common.utils.JwtUtil;
import com.qf.user.manager.bean.LoginUser;
import com.qf.user.manager.service.UserService;
import io.jsonwebtoken.Claims;
import okhttp3.Interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证过滤器
 * 1. 对请求头中的token进行解析
 * 2. 将解析到的UserId到数据库中进行查询
 * 3. 将查询到的用户, 角色, 权限等信息放入SpringSecurityContextHolder容器中保存
 * @author 千锋健哥
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    //前端中存入localStore中的key
    @Value("${jwt.token-header}")
    private String token;

    @Autowired
    private UserService userService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        //1. 获取当前用户访问的url地址
        String path = request.getRequestURI();

        //2. 如果是登录路径, 注销路径, 无条件放行
        if (path.contains("/user/auth")) {
            chain.doFilter(request, response);
            return;
        }

        //3. 获取请求头中的token令牌
        String token = request.getHeader(this.token);

        //4. 解析jwt
        if (StringUtils.isNotEmpty(token)) {

            String userName = null;
            try {
                Claims claims = JwtUtil.parseJWT(token);
                userName = claims.getSubject();
            } catch (Exception e) {
                //5. 如果解析失败, 不允许登录
                WriteJSON(request, response, new AccessDeniedException("非法访问, 请从新登录!"));
                return;
            }

            //6. 根据用户名, 获取用户的用户对象, 角色对象, 权限对象
            //根据用户名查询用户对象
            QfUser qfUser = userService.getUserByUserName(userName);
            //根据用户名查询用户的菜单
            List<String> menuList = userService.findUserMenuByUserName(userName);

            //7. 将用户的角色权限对象封装到SpringSecurity的权限集合中
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            if (menuList != null) {
                for (String menu : menuList) {
                    authorities.add(new SimpleGrantedAuthority(menu));
                }
            }

            //实现SpringSecurity框架的UserDetail实体类, 传入用户对象和权限集合对象
            LoginUser loginUser = new LoginUser(qfUser, authorities);

            //8. 对比前端传入的请求头中的token令牌和SpringSecurity容器中的数据是否一致
            //将用户对象, 权限集合放入SpringSecurity容器中保存更新
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            //9. 放行
            chain.doFilter(request, response);


        }




    }


    /**
     * json处理
     * @param request
     * @param response
     * @param obj
     * @throws IOException
     * @throws ServletException
     */
    private void WriteJSON(HttpServletRequest request,
                           HttpServletResponse response,
                           Object obj) throws IOException, ServletException {
        //这里很重要，否则页面获取不到正常的JSON数据集
        response.setContentType("application/json;charset=UTF-8");

        //跨域设置
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Method", "POST,GET");
        //输出JSON
        PrintWriter out = response.getWriter();
        out.write(JsonUtil.toJsonString(obj));
        out.flush();
        out.close();
    }

}
